package org.jflame.commons.config;

import java.util.Arrays;

import org.apache.commons.lang3.ArrayUtils;
import org.jflame.commons.codec.Transcoder;
import org.jflame.commons.crypto.DelegateEncryptor;
import org.jflame.commons.crypto.EncryptException;
import org.jflame.commons.util.CharsetHelper;
import org.jflame.commons.util.StringHelper;

public class EncryptedValueResolver {

    private DelegateEncryptor cipherer;
    private String cipherPrefix = "#ENC:";

    public EncryptedValueResolver() {
    }

    public EncryptedValueResolver(DelegateEncryptor cipherer) {
        this.cipherer = cipherer;
    }

    /**
     * 给定密钥使用aes/ecb加密算法构造一个EncryptedValueResolver
     * 
     * @param secretKey 密钥
     */
    public static EncryptedValueResolver buildByAES(String secretKey) {
        return new EncryptedValueResolver(DelegateEncryptor.AES(secretKey));
    }

    /**
     * 给定用户口令,使用PBEWithMD5AndDES密算法构造一个EncryptedValueResolver
     * 
     * @param password 用户口令
     * @return
     */
    public static EncryptedValueResolver buildByPBE(String password) {
        byte[] salt = genSalt(password, 8);// 由用户口令生成一个固定的盐
        return new EncryptedValueResolver(DelegateEncryptor.PBE(password, salt, 50));
    }

    private static byte[] genSalt(final String password, final int genSize) {
        String factor;
        if (password.length() < genSize) {
            factor = StringHelper.repeat(password, Math.floorDiv(genSize, password.length() + 1));
        } else {
            factor = password.substring(password.length() - genSize);
        }
        byte[] keyBytes = Transcoder.encodeBase64(CharsetHelper.getUtf8Bytes(factor));
        ArrayUtils.reverse(keyBytes);
        keyBytes = Transcoder.encodeBase64(keyBytes);
        return Arrays.copyOf(keyBytes, genSize);
    }

    public String getCipherPrefix() {
        return cipherPrefix;
    }

    /**
     * 设置加密值的标识前缀
     * 
     * @param cipherPrefix 前缀
     */
    public void setCipherPrefix(String cipherPrefix) {
        this.cipherPrefix = cipherPrefix;
    }

    public void setCipherer(DelegateEncryptor cipherer) {
        this.cipherer = cipherer;
    }

    public boolean isEncryptedValue(String value) {
        return value != null && value.startsWith(cipherPrefix);
    }

    /**
     * 解密
     * 
     * @param value
     * @return
     */
    public String resolve(String value) {
        if (cipherer != null && isEncryptedValue(value)) {
            try {
                return cipherer.decrypt(value.substring(cipherPrefix.length()));
            } catch (EncryptException e) {
                e.printStackTrace();// 解密失败,返回原值
            }
        }
        return value;
    }

    /**
     * 加密
     * 
     * @param value
     * @return
     * @throws EncryptException
     */
    public String encryptValue(String value) throws EncryptException {
        return cipherPrefix + cipherer.encrypt(value);
    }
}
